
import java.awt.Canvas;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.util.Stack;

import javax.naming.Context;

public class GraphicalView extends Canvas implements Observer, MouseListener {



	private Document doc = null;

	public RemoteObserver model = null;

	private ButtonStrip bs = null;

	//private ArrayList<Memento> memes = null; //hehe

	private Stack<Memento> undoMems = null;


	private Stack<Memento> redoMems = null;

	private boolean undo = false;

	/**
	 * 
	 */
	private static final long serialVersionUID = 608480498208087429L;


	public GraphicalView(RemoteObserverInterface obs, ButtonStrip bs) {
		super();
		this.setSize(600, 600);

		this.bs = bs;



		this.model = (RemoteObserver)obs;

		((RemoteObserver)obs).Attach(this);

		this.doc = ((RemoteObserver)obs).getDoc();


		this.setUndoMems(new Stack<Memento>());

		this.setRedoMems(new Stack<Memento>());


		System.out.println("Creating graphical view");
		System.out.println("With docname: "+this.doc.name);



		setBackground(Color.white);

		this.addMouseListener(this);
		
	}


	public void paint (Graphics g) {

		//visit the document and draw stuff

		//g.clearRect(0, 0, getWidth(), getHeight());//g.drawRect(10, 10, 10, 10); //temp drawing


		if(this.doc.getRootobj().children.size() == 0) {
			g.drawString("Hello World!\n quack", 200, 340);
		}

		paintStuff(this.doc.getRootobj(), g);

	}


	/**
	 * Observer method it is invoked by the model to notify that it has changed
	 * and that this view needs to update its state to be consistent with the new
	 * model state
	 */
	@Override
	public void Update(Subject sub) {

		//1st get the new doc



		this.doc = sub.getDoc();
		if(!this.undo) {
			this.undoMems.push(this.model.CreateMemento());
			//this.undoMems.push(this.model.CreateMemento());
			this.redoMems.clear();
		}
		System.out.println("Updating view: "+this.doc.name);
		this.undo = false;
		//repaint();
		repaint();


	}

	@Override
	public void mouseClicked(MouseEvent arg0) {
		// TODO Auto-generated method stub
		//System.out.println("mooo");

		//Document tmp =  new Document("moo doc");
		//this.doc.getRootobj().addElement(new Circle(arg0.getX(), arg0.getY()));

		//tmp.getRootobj().addElement(new Circle(20, 20));

		//this.doc = tmp;






		//model.setDoc(this.doc);


	}

	@Override
	public void mouseEntered(MouseEvent arg0) {
		// TODO Auto-generated method stub

	}

	@Override
	public void mouseExited(MouseEvent arg0) {
		// TODO Auto-generated method stub

	}

	@Override
	public void mousePressed(MouseEvent arg0) {
		// TODO Auto-generated method stub

	}

	@Override
	public void mouseReleased(MouseEvent arg0) {
		// TODO Auto-generated method stub

		//this.doc.getRootobj().addElement(new Circle(arg0.getX(), arg0.getY()));


		//GraphicsObject tmp = this.bs.selObj;

		//tmp.xpos = arg0.getX();
		//tmp.ypos = arg0.getY();
		//	this.doc.getRootobj().addElement(tmp);

		Class<?> cl = this.bs.objs.get(this.bs.selObj);

		if(this.bs.selObj == null) {
			System.out.println("Select a drawing object first!");
			return;

		}

		try {
			GraphicsObject go =  (GraphicsObject) cl.newInstance();

			go.xpos = arg0.getX();
			go.ypos = arg0.getY();


			
			this.doc.getRootobj().addElement(go);

			this.getUndoMems().push(this.model.CreateMemento());
			this.redoMems.clear();


			System.out.println("Mementos stored: "+this.getUndoMems().size());

			model.setDoc(this.doc);
			
			
			this.undo = true;
			//this.bs.selObj = null;
			//System.out.println("Undo stack size: "+this.undoMems.size());
		} catch (InstantiationException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (IllegalAccessException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}


	}

	public void undo() {

		if(this.getUndoMems().size()<2) {
			return;
		}
		//this.undoMems.push(this.model.CreateMemento());
		this.getRedoMems().push(this.getUndoMems().pop());
		//this.redoMems.clear();.

		this.undo = true;

		this.model.SetMemento(this.getUndoMems().peek());

		System.out.println("Undo stack size: "+this.getUndoMems().size());
		System.out.println("Redo stack size: "+this.getRedoMems().size());
	}

	public void redo() {

		if(this.getRedoMems().isEmpty()) {
			return;

		}

		this.getUndoMems().push(this.getRedoMems().pop());

		this.undo = true;
		
		this.model.SetMemento(this.getUndoMems().peek());
		System.out.println("Redo stack size: "+this.getRedoMems().size());
		
	}






	private void paintStuff(GlobalObject obj, Graphics g) {

		//DefaultMutableTreeNode tmp = null;

		if (obj instanceof ObjectGroup) {
			//tmp = new DefaultMutableTreeNode("group");
			//System.out.println("Creating node");
			for (GlobalObject ob : ((ObjectGroup) obj).children) {
				paintStuff(ob, g);
			}
		} else {
			System.out.println("Creating leaf "+obj.getClass().getSimpleName());
			((GraphicsObject)obj).Draw(g);
		}
	}


	public void setRedoMems(Stack<Memento> redoMems) {
		this.redoMems = redoMems;
	}


	public Stack<Memento> getRedoMems() {
		return redoMems;
	}


	public void setUndoMems(Stack<Memento> undoMems) {
		this.undoMems = undoMems;
	}


	public Stack<Memento> getUndoMems() {
		return undoMems;
	}


}
